﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="NetworkUtils.cs" company="TomCorp">
//   Tom
// </copyright>
// <summary>
//   Defines the NetworkUtils type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace GeoCoder {
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    using Model;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;

    /// <summary>
    /// The network utils.
    /// </summary>
    public static class NetworkUtils {
        /// <summary>
        /// The reporting event handler.
        /// </summary>
        public static event EventHandler<ReportingEventArgs> Reporting = delegate { };

        /// <summary>
        /// The fetch from server and parse.
        /// </summary>
        /// <param name="url">
        /// The url.
        /// </param>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <param name="username">
        /// The username.
        /// </param>
        /// <param name="password">
        /// The password.
        /// </param>
        /// <param name="webProxy">
        /// The web Proxy.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here.")]
        public static async Task<List<HeroldDataSet>> FetchFromServerAndParse(string url, string parameters, string username, string password, WebProxy webProxy = null) {
            var response = await QueryServer(url, parameters, username, password, webProxy);
            Reporting(null, new ReportingEventArgs { Message = "Response received, parsing JSON" });
            var jObject = JObject.Parse(response);

            var dataSets = new List<HeroldDataSet>();
            foreach (var jToken in jObject["searchResponse"]["searchResultLists"]) {
                var searchType = jToken["searchType"].ToString();
                var dataSet = new HeroldDataSet { HeroldData = new List<HeroldData>() };
                if (searchType == "yp")
                    dataSet.Type = SearchType.YellowPages;
                else if (searchType == "wp")
                    dataSet.Type = SearchType.PhoneBook;
                dataSet.TotalCount = (int)jToken["totalNumberOfHits"];
                if (dataSet.TotalCount == 0) {
                    Reporting(null, new ReportingEventArgs { Message = "Records expected but none received..." });
                }

                // try to parse the results
                Reporting(null, new ReportingEventArgs { Message = "Parsing results.." });
                var serializer = new JsonSerializer();
                var resultArray = jToken["normalResults"];
                var resultList = serializer.Deserialize<List<HeroldData>>(resultArray.CreateReader());
                dataSet.HeroldData = resultList;
                Reporting(null, new ReportingEventArgs { Message = "Parsing finished. Parsed " + resultList.Count + " objects." });
                dataSets.Add(dataSet);
            }

            return dataSets;
        }

        /// <summary>
        /// Requests a JSON file from a remote server
        /// </summary>
        /// <param name="url">
        /// The url.
        /// </param>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <param name="username">
        /// The username.
        /// </param>
        /// <param name="password">
        /// The password.
        /// </param>
        /// <param name="webProxy">The WebProxy</param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private static async Task<string> QueryServer(string url, string parameters, string username, string password, WebProxy webProxy = null) {
            parameters = Uri.EscapeUriString(parameters);
            string response;
            using (var webClient = new WebClient()) {
                if (webProxy != null)
                    webClient.Proxy = webProxy;
                var credentials =
                    Convert.ToBase64String(Encoding.ASCII.GetBytes(username + ":" + password));
                webClient.Headers[HttpRequestHeader.Authorization] = "Basic " + credentials;
                webClient.Headers[HttpRequestHeader.UserAgent] =
                    "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25";
                webClient.Headers[HttpRequestHeader.ContentType] =
                    "application/x-www-form-urlencoded; charset=utf-8";

                Reporting(null, new ReportingEventArgs { Message = string.Format("Connecting to {0}. POST request parameters: {1}", url, parameters) });
                response = await webClient.UploadStringTaskAsync(url, parameters);
            }

            return response;
        }

        /// <summary>
        /// The reporting event args.
        /// </summary>
        public class ReportingEventArgs : EventArgs {
            /// <summary>
            /// Gets or sets the message.
            /// </summary>
            public string Message { get; set; }
        }
    }
}
